var mongodb = require('mongodb');
var redis   = require('redis');
var http    = require('http');
var util    = require('util');
var sys     = require('sys');
var fs      = require('fs');
var url     = require('url');
var qs      = require('querystring');
var zlib    = require('zlib');

var common  = require('../js/common.js');
var csv     = require('../js/csv.js');

function loadConf() {
    // 加载配置文件
    global.gConfGlobalServer = new csv.GlobalCSV('conf/globalserver.dat');
    gConfGlobalServer.ServerStartTime = csv.parseDate(gConfGlobalServer.ServerStartTime);
    gConfGlobalServer.FirstLeagueWarTime = csv.parseDate(gConfGlobalServer.FirstLeagueWarTime);
    gConfGlobalServer.SystemRewardTime = csv.parseDate(gConfGlobalServer.SystemRewardTime);
    gConfGlobalServer.FirstServerWarTime = csv.parseDate(gConfGlobalServer.FirstServerWarTime);

    global.gConfGlobal = new csv.GlobalCSV('conf/global.dat');

    global.gConfLevel = new csv.CommonCSV('conf/level.dat', ['Level']);
    global.gConfTavern = new csv.CommonCSV('conf/tavern.dat', ['Type','CashTimes']);
    global.gConfRole = new csv.RoleCSV('conf/role.dat', ['Id']);
    global.gConfRoleLevel = new csv.CommonCSV('conf/rolelevel.dat',['Level']);
    global.gConfSoldier = new csv.CommonCSV('conf/soldier.dat', ['Soldier','Level']);
    global.gConfGrouth = new csv.CommonCSV('conf/grouth.dat', ['Quantity']);
    global.gConfSkill = new csv.CommonCSV('conf/skill.dat', ['Soldier','Skill']);
    global.gConfEquip = new csv.CommonCSV('conf/equip.dat', ['Level']);
    global.gConfStrengthen = new csv.CommonCSV('conf/strengthen.dat', ['Strength']);
    global.gConfWeapon = new csv.CommonCSV('conf/weapon.dat', ['Strength']);
    global.gConfArmor = new csv.CommonCSV('conf/armor.dat', ['Strength']);
    global.gConfAccessory = new csv.CommonCSV('conf/accessory.dat', ['Strength']);
    global.gConfSkillEffect = new csv.CommonCSV('conf/skilleffect.dat',
                                                 ['Soldier','Skill','Level']);
    global.gConfMonster = new csv.CommonCSV('conf/monster.dat',['Id']);
    global.gConfBattle  = new csv.PVECSV('conf/battle.dat',['Id']);
    global.gConfTower = new csv.PVECSV('conf/tower.dat',['Id']);
    global.gConfLeagueBoss = new csv.PVECSV('conf/leagueboss.dat',['Level']);
    global.gConfTomb = new csv.PVECSV('conf/tomb.dat', ['Id']);
    global.gConfWorldBoss = new csv.PVECSV('conf/worldboss.dat', ['Id']);
    global.gConfKillGeneral = new csv.CommonCSV('conf/killgeneral.dat',['Id']);
    global.gConfMaterial = new csv.CommonCSV('conf/material.dat', ['Id']);

    global.gConfGem = new csv.CommonCSV('conf/gem.dat', ['Id']);
    
    global.gConfTavern = new csv.TavernCSV('conf/tavern.dat', ['Level']);
    global.gConfTraining = new csv.TavernCSV('conf/training.dat', ['Id']);
    global.gConfBusiness = new csv.BusinessCSV('conf/business.dat', ['Id']);
    global.gConfTech = new csv.CommonCSV('conf/tech.dat', ['Id']);
    global.gConfShop = new csv.CommonCSV('conf/shop.dat', ['Id']);
    global.gConfSoldierInit = new csv.CommonCSV('conf/soldierinit.dat', ['Soldier']);

    global.gConfRank = new csv.CommonCSV('conf/rank.dat', ['Id']);
    global.gConfMine = new csv.CommonCSV('conf/mine.dat', ['Quantity']);

    global.gConfDailyTask = new csv.DailyTaskCSV('conf/dailytask.dat', ['Id']);
    global.gConfTaskReward = new csv.CommonCSV('conf/taskreward.dat', ['Score']);

    global.gConfOnlineReward = new csv.CommonCSV('conf/onlinereward.dat', ['Time']);
    global.gConfBuy = new csv.CommonCSV('conf/buy.dat', ['Times']);
    global.gConfLevelPack = new csv.CommonCSV('conf/levelpack.dat',['Level']);
    global.gConfTask = new csv.CommonCSV('conf/task.dat',['Id']);
    
    global.gConfSign = new csv.CommonCSV('conf/sign.dat',['Id']);
    global.gConfLogin = new csv.CommonCSV('conf/login.dat',['Id']);

    global.gConfSystemReward = new csv.CommonCSV('conf/systemreward.dat',['Id']);
    global.gConfSoul = new csv.CommonCSV('conf/soul.dat',['Level']);

    global.gConfLeagueLevel = new csv.CommonCSV('conf/leaguelevel.dat',['Level']);
    global.gConfLeagueTech = new csv.CommonCSV('conf/leaguetech.dat',['Id','Level']);
    global.gConfLeagueReward = new csv.CommonCSV('conf/leaguereward.dat',['Id']);
    global.gConfLeagueBossReward = new csv.CommonCSV('conf/leaguebossreward.dat', ['Id']);

    global.gConfVip = new csv.CommonCSV('conf/vip.dat',['Level']);
    
    global.gConfActivities = new csv.ActivityCSV('conf/activities.dat',['Key']);
    global.gConfActivitySchedule = new csv.CommonCSV('conf/activities_schedule.dat',['Id']);
    global.gConfAvSeven = new csv.CommonCSV('conf/avseven.dat',['Day']);
    global.gConfAvLevelTop = new csv.CommonCSV('conf/avleveltop.dat',['Level']);
    global.gConfAvLuckyWheel = new csv.CommonCSV('conf/avluckywheel.dat',['ConfId','Star']);
    global.gConfAvInvest = new csv.CommonCSV('conf/avinvest.dat',['Id', 'InvestDay']);
    global.gConfAvLimitBuy = new csv.CommonCSV('conf/avlimitbuy.dat',['Id']);
    global.gConfAvSurprise = new csv.CommonCSV('conf/avsurprise.dat', ['ConfId','Grid']);
    global.gConfAvCrazyRank = new csv.CommonCSV('conf/avcrazyrank.dat', ['Rank']);
    global.gConfAvCrazySend = new csv.AvCrazySendCSV('conf/avcrazysend.dat', ['DebrisNum']);
    global.gConfAvFeed = new csv.CommonCSV('conf/avfeed.dat', ['Id']);
    global.gConfAvYellowDiamond = new csv.CommonCSV('conf/avyellowdiamond.dat', ['Id']);
    global.gConfAvCharge = new csv.CommonCSV('conf/avcharge.dat',['ConfId','Id']);
    global.gConfAvWish = new csv.CommonCSV('conf/avwish.dat', ['Id']);
    global.gConfAvYellowCharge = new csv.CommonCSV('conf/avyellowcharge.dat',['Id']);
    global.gConfAvTower = new csv.CommonCSV('conf/avtower.dat',['Floor']);
    global.gConfAvTowerRank = new csv.CommonCSV('conf/avtowerrank.dat',['Rank']);
    global.gConfAvFightForce = new csv.CommonCSV('conf/avfightforce.dat',['FightForce']);
    global.gConfAvFightForceRank = new csv.CommonCSV('conf/avfightforcerank.dat',['Rank']);
    global.gConfAvForgeLevel = new csv.CommonCSV('conf/avforgelevel.dat',['Id']);
    global.gConfAvPlayerLevel = new csv.CommonCSV('conf/avplayerlevel.dat',['Level']);
    global.gConfAvLevelRank = new csv.CommonCSV('conf/avlevelrank.dat',['Rank']);
    global.gConfAvGroupOn = new csv.CommonCSV('conf/avgroupon.dat',['Day']);
    global.gConfAvWestern = new csv.AvWesternCSV('conf/avwestern.dat',['Id']);
    global.gConfAvWealth = new csv.CommonCSV('conf/avwealth.dat',['Id']);
    global.gConfAvPay = new csv.CommonCSV('conf/avpay.dat',['Day','Pay']);
    global.gConfAvPayRank = new csv.CommonCSV('conf/avpayrank.dat',['Id']);
    global.gConfAvGemBuy = new csv.CommonCSV('conf/avgembuy.dat',['Id']);

    global.gConfCombine = new csv.CombineCSV('conf/combine.dat',['Id']);
    global.gConfGloryShop = new csv.CommonCSV('conf/gloryshop.dat',['Id']);

    global.gConfGradeLevel = new csv.CommonCSV('conf/gradelevel.dat',['Level']);
    global.gConfLeagueWarCity = new csv.CommonCSV('conf/leaguewarcity.dat',['Id']);
    global.gConfLeagueWarRank = new csv.CommonCSV('conf/leaguewarrank.dat',['Rank']);

    global.gConfBlackShop = new csv.CommonCSV('conf/blackshop.dat',['Id']);
    global.gConfBox = new csv.CommonCSV('conf/box.dat', ['Id']);

    global.gConfSlot = new csv.CommonCSV('conf/slot.dat',['Id', 'Index']);

    global.gConfTombReward = new csv.CommonCSV('conf/tombreward.dat', ['Id', 'Pos']);

    global.gConfCard = new csv.CommonCSV('conf/card.dat', ['Id']);

    global.gConfAchieveGoal = new csv.CommonCSV('conf/achieve_goal.dat', ['StageId', 'GoalId']);
    global.gConfAchieveStage = new csv.CommonCSV('conf/achieve_stage.dat', ['StageId']);

    global.gConfServerWarSchedule = new csv.CommonCSV('conf/serverwarschedule.dat', ['Progress']);
    global.gConfServerWarReward = new csv.CommonCSV('conf/serverwarreward.dat', ['Rank']);
    global.gConfServerWarSupport = new csv.CommonCSV('conf/serverwarsupport.dat', ['Rank']);

    global.gConfWorldBossReward = new csv.CommonCSV('conf/worldbossreward.dat', ['Week', 'Rank']);

    global.gConfDayWheel = new csv.CommonCSV('conf/daywheel.dat', ['Day']);
    global.gConfDayWheelReward = new csv.CommonCSV('conf/daywheelreward.dat', ['Id']);

    global.gConfPet = new csv.CommonCSV('conf/pet.dat', ['Level']);
    global.gConfPetSkillEffect = new csv.CommonCSV('conf/petskilleffect.dat', ['Skill', 'Level']);

    global.gConfHorse = new csv.CommonCSV('conf/horse.dat',['Id']);
    global.gConfHarness = new csv.CommonCSV('conf/harness.dat',['Id']);
    global.gConfHarnessLevel = new csv.CommonCSV('conf/harnesslevel.dat',['Level']);
    global.gConfHorseLevel = new csv.CommonCSV('conf/horselevel.dat',['Level']); 
    global.gConfHorseSell = new csv.CommonCSV('conf/horsesell.dat',['Level']);
}

function loadDB(callback, poolSize) {
    poolSize = poolSize || 2;

    var mongoServer = null;
    if( config.MongodbSets ) {
        var servers = [];
        config.MongodbSets.forEach(function(serverConf){
            servers.push(new mongodb.Server(serverConf[0], serverConf[1],
                        {auto_reconnect:true, poolSize:poolSize}));
        });
        mongoServer = new mongodb.ReplSetServers(servers);
    }else{
        mongoServer = new mongodb.Server(config.MongodbHost, config.MongodbPort,
                        {auto_reconnect:true, poolSize:poolSize});
    }

    var db = new mongodb.Db(config.MongodbName, mongoServer, 
                    {'native_parser':true, 'w':1, 'wtimeout':10, 'fsync':false});
    db.open(function(err, db) {
        if( err ) {
            ERROR(err);
            process.exit(-1);
        }

        callback && callback(db);
    });
}

function loadCache(callback) {
    var client = redis.createClient(config.RedisPort, config.RedisHost);
    client.select(config.RedisId, function(err){
        if( err ) {
            ERROR(err);
            process.exit(-1);
        }
    });

    client.on('ready', function(){
        callback && callback(client);
    });

    client.on('error', function(e){
        ERROR(e);
    });
}

// 创建web服务器
function startWebServer(serverName, port, ip, handler, onExit) {
    var isExiting = false;
    var server = http.createServer(function(req, res) {
        if( isExiting ) {
            req.connection.destroy();
            return;
        }

        var body = '';
        req.on('data', function(chunk) {
            body += chunk;
            // POST请求不能超过100K
            if( body.length > 102400 ) {
                req.connection.destroy();
                return;
            }
        });

        req.on('end', function() {
            if( req.url == '/crossdomain.xml') {
                res.writeHead(200, common.defaultHeaders);
                res.end(common.defaultCrossDomain);
                return;
            }

            var rawData = '';
            if( req.method == 'POST' ) {
                rawData = body;
            }else{
                rawData = url.parse(req.url).query;
            }

            query = qs.parse(rawData);
            res._query = query;
            res._time = +(new Date());
            //res._compress = req.headers['accept-encoding'] || '';

            handleReq(query, res, handler);
        });

    });
    server.listen(port, ip);
    
    var pidFile = serverName + '.pid';
    process.on('SIGINT', beforExit);
    process.on('SIGTERM', beforExit);

    process.on('uncaughtException', function (err) {  
        ERROR(err.stack);    
    });

    function beforExit() {
        INFO(serverName + ' begin shutdown');
        isExiting = true;

        if( onExit ) {
            onExit(endExit);
        }else{
            endExit();
        }
    }

    function endExit() {
        fs.existsSync(pidFile) && fs.unlinkSync(pidFile);
        INFO(serverName + ' end shutdown');
        process.exit();
    }

    INFO(serverName + ' start');
    fs.writeFileSync(pidFile, process.pid, 'utf8');

    return server;
}

function handleReq(query, res, handler) {
    var code = 1;
    var desc = '';

    query.uid = +query.uid;
    if( !query.mod ) {
        desc = 'no mod';    
    }else if( !query.act ) {
        desc = 'no act';
    }else if( !query.uid ) {
        desc = 'no uid';
    }else if( !query.args ) {
        desc = 'no args';
    }else{
        try{
            query.args = JSON.parse(query.args); 
            code = 0;
        }catch(error){
            desc = 'args not in json format';
        }
    }

    var resp = {
        'code': code, 
        'desc': desc, 
        'mod': query.mod, 
        'act': query.act, 
        'args': query.args,
        'data': {}
    };

    if( resp.code != 0 ) {
        onReqHandled(res, resp);
        return;
    }
    handler(query, res, resp);
}

global.onReqHandled = function(res, data, isCompress) {
    if( !data.hasOwnProperty('code') ) {
        data.code = 1;
        data.desc = 'no code';
    }

    if( !data.hasOwnProperty('desc') ) {
        data.desc = '';
    }

    data.serverTime = common.getTime();
    var strData = JSON.stringify(data)
    
    if( isCompress && !config.NotGzip && strData.length > 1024 ) {
        zlib.gzip(strData, function(err, buf){
            res.writeHead(200, common.gzipHeaders);
            res.end(buf);
        });
    }else{
        res.writeHead(200, common.defaultHeaders);
        res.end(strData);
    }
    
    var timeCost = +(new Date()) - res._time;
    var query = res._query;

    LOG(util.format('%s %s %s %s %j %d %d %s', query.uid, query.mod, query.act,
                    query.seq||0, query.args, timeCost, data.code, data.desc));
}

global.reportQQ = function(action, args, pf){
    if( !config.Pay ) return;

    /*
    QQ空间为1；
    腾讯朋友为2；
    腾讯微博为3；
    Q+平台为4；
    手机QQ空间为8；
    手机腾讯朋友为9；
    QQGame为10；
    3366为11；
    QQGame官网为12；
    漫游为15；
    游戏人生为16；
    游戏联盟为17 
    */
    var domain = 1;
    if( pf == 'pengyou' ) {
        domain = 2;
    }else if( pf == '3366' ) {
        domain = 11;
    }

    args['appid'] = '100712667';
    args['userip'] = 1245633332;
    args['svrip'] = 1434394239;
    args['time'] = common.getTime();
    args['domain'] = domain;
    args['worldid'] = config.ServerId;
    args['opopenid'] = args['opuid'];

    var strArgs = qs.stringify(args);
    http.get(util.format("http://tencentlog.com/stat/report_%s.php?%s", action, strArgs));
}

global.requestUniverse = function(query, resp, callback){
    var options = {
        host: config.UniverseHost,
        port: config.UniversePort,
        path: '/',
        method: 'POST'
    };

    var req = http.request(options, function(res) {
        var chunks = [];
        res.on('data', function(chunk){
            chunks.push(chunk);
        });

        res.on('end', function(){
            var data = Buffer.concat(chunks).toString();
            var UniverseResp = null;
            try{
                UniverseResp = JSON.parse(data); 
            }catch(error){
                ERROR('universe resp '+data);
                UniverseResp = null;
            }

            if( !UniverseResp ) {
                resp.code = 1; resp.desc='request universe error';
            }else{
                resp.code = UniverseResp.code;
                resp.desc = UniverseResp.desc;
                resp.data = UniverseResp.data;
            }

            callback && callback();
        });
    });

    req.on('error', function(err){
        resp.code = 1;
        resp.desc = 'request universe error';
        callback && callback(null);
    });

    req.end('mod={0}&act={1}&uid={2}&args={3}'.format(query.mod, query.act,
                query.uid, JSON.stringify(query.args)));
    req.end();
}

exports.loadDB = loadDB;
exports.loadCache = loadCache;
exports.loadConf = loadConf;
exports.startWebServer = startWebServer;
